/**
 * Sleek Mobile
 *
 * 
 **/
var SleekMobile = {
	// Config
	loadingTxt:			'Loading...', 
	errorTxt:			'Error loading page', 

	defaultTransition:	'slide', 
	transitionDuration:	200, 

	messageHideDelay:	4000, 

	// System stuff 
	logs:				[], 
	pageLoadCallbacks:	{}, 

	messaHideTimeout:	false, 
	initialURL:			location.href, 
	hasPopped:			false, 

	init: function () {
		SleekMobile.hideAddressBar();
		SleekMobile.hijaxRequests();
		SleekMobile.backButton();
	}, 

	// Logging
	log: function (msg) {
		console.log(msg);
		SleekMobile.logs.push(msg);
	}, 

	dir: function (obj) {
		console.dir(obj);
		SleekMobile.logs.push(obj);
	}, 

	getLog: function () {
		return SleekMobile.logs.join('\n');
	}, 

	// Hides the address bar of the browser
	hideAddressBar: function () {
		$(window).load(function () {
			SleekMobile.log('Hiding address bar');
			window.scrollTo(0, 1);
		});
	}, 

	// Updates the URL
	updateURL: function (url, transition, reversed) {
		if (('pushState' in window.history)) {
			SleekMobile.log('Updating history state: ' + url);
			window.history.pushState({url: url, transition: transition, reversed: reversed}, '', url);
		}
	}, 

	// Makes the 'back' and 'forward' buttons work with ajax
	// TODO: Fix coming back from external page + 
	// proper back/forward transitions for each button based on how page was previously entered + 
	// ignoring #-requests
	backButton: function () {
		if (('pushState' in window.history)) {
			window.onpopstate = function (e) {
				SleekMobile.log('--------------------------\nPopState event fired');

				if (e.state && e.state.url) {
					SleekMobile.log('State set:');
					SleekMobile.dir(e.state);
					SleekMobile.changePage(e.state.url, e.state.transition, !e.state.reversed, false);
				}
				else if (SleekMobile.hasPopped && location.href == SleekMobile.initialURL) {
					SleekMobile.log('No state set but current location is initial location, loading initialURL: ' + SleekMobile.initialURL);
					SleekMobile.changePage(SleekMobile.initialURL, SleekMobile.defaultTransition, true, false);
				}
				else if (!SleekMobile.hasPopped) {
					SleekMobile.log('Was initial PopState - doing nothing');
				}
				else {
					SleekMobile.log('No state and not first page - do nothing');
				}

				SleekMobile.hasPopped = true;
			};
		}
	}, 

	// Adds a callback function to 'page' (ID of [data-role="page"] element)
	addPageLoadCallback: function (page, func) {
		if (!SleekMobile.pageLoadCallbacks.page) {
			SleekMobile.pageLoadCallbacks.page = [];
		}

		SleekMobile.log('--------------------------\nAdding pageLoadCallback to page: ' + page);
		SleekMobile.pageLoadCallbacks.page.push(func);
	}, 

	// Runs callback functions added to a 'page'
	runPageLoadCallbacks: function (page, el) {
		if (SleekMobile.pageLoadCallbacks.page) { // TODO: Surely .page should be [page] - no??
			for (var i in SleekMobile.pageLoadCallbacks.page) {
				SleekMobile.log('--------------------------\nRunning pageLoadCallback for page: ' + page);
				SleekMobile.pageLoadCallbacks.page[i](el);
			}
		}
	}, 

	// Shows a system message
	showMessage: function (txt, type, delay) {
		var ms	= ((typeof(delay) == 'undefined') ? SleekMobile.messageHideDelay : ((delay !== false) ? delay : false));
		var msg	= $('#sleek-mobile-message');

		if (!msg.length) {
			msg = $('<section id="sleek-mobile-message"></section>').appendTo(document.body);
		}

		setTimeout(function () {
			msg.attr('class', 'visible ' + (type || '')).html(txt);
		}, 1);

		SleekMobile.log('--------------------------\nShowing message: ' + txt);

		if (ms) {
			if (SleekMobile.messageHideTimeout) {
				SleekMobile.log('Clearing previous message timout');
				clearTimeout(SleekMobile.messageHideTimeout);
			}

			SleekMobile.log('Setting hide timeout to ' + ms + ' ms');
			SleekMobile.messageHideTimeout = setTimeout(function () {
				SleekMobile.hideMessage();
			}, ms + 1);
		}
	}, 

	// Hides previously shown message
	hideMessage: function () {
		SleekMobile.log('--------------------------\nHiding message');
		$('#sleek-mobile-message').removeClass('visible');
	}, 

	// Hijaxes link and form requests
	hijaxRequests: function () {
		$('a:not([rel="external"]):not([href^="#"]):not([href^="http:"])').live('click', function (e) {
			e.preventDefault();

			var el		= $(this);
			var url		= el.attr('href');
			var trans	= false; // TODO: read from $.data
			var rev		= false; // TODO: --"--

			if (url.indexOf('#') == -1) {
				SleekMobile.log('--------------------------\nLink clicked, changing page to:' + url);
				SleekMobile.changePage(url, trans, rev, true);
			}
		});

		$('form:not([rel="external"])').live('submit', function (e) {
			e.preventDefault();

			var el		= $(this);
			var url		= el.attr('action');
			var type	= el.attr('method') || 'post'; // TODO: Is 'post' default if method is not set?
			var data	= el.serialize();
			var trans	= false; // TODO: read from $.data
			var rev		= false; // TODO: --"--

			SleekMobile.log('--------------------------\nForm submitted, changing page to: ' + url);
			SleekMobile.changePage(url, trans, rev, true, type, data);
		});
	}, 

	// Changes from one page to another
	changePage: function (url, transition, reversed, updateURL, type, data) {
		var reScript	= /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;
		var oldPage		= $('[data-role="page"]').eq(0);

		SleekMobile.showMessage(SleekMobile.loadingTxt, 'loading', false);

		SleekMobile.log('--------------------------\nAjaxing in new page: ' + url);

		$.ajax(url, {
			data: data || null, 
			type: type || 'GET', 
			success: function (newPage) {
				SleekMobile.log('Successfully loaded the page');

				var tmp			= $('<div/>').append(newPage.replace(reScript, ''));
				var newPage		= tmp.find('[data-role="page"]').insertAfter(oldPage).hide();
				var newTitle	= tmp.find('title').text();

				$('title').text(newTitle);
				SleekMobile.hideMessage();
				SleekMobile.transition(oldPage, newPage, transition, reversed);

				if (updateURL) {
					SleekMobile.updateURL(url, transition, reversed);
				}
			}, 
			error: function () {
				$('title').text(SleekMobile.errorTxt);
				SleekMobile.showMessage(SleekMobile.errorTxt, 'error');
			}
		});
	}, 

	// Transitions from one page to another
	transition: function (from, to, transition, reversed) {
		var wrap	= $('[data-role="pages"]').eq(0);
		var trans	= transition || SleekMobile.defaultTransition;
		var rev		= reversed ? 'reverse-' : '';

		SleekMobile.log('--------------------------\nStarting transition: ' + trans + ' in direction: ' + (reversed ? 'reversed' : 'normal'));

		// 1. Create dummy page same size as biggest page in transition
		var toDim	= {
			width:	to.show().outerWidth(), 
			iWidth:	to.innerWidth(), 
			height:	to.outerHeight()
		};
		var fromDim = {
			width:	from.show().outerWidth(), 
			iWidth:	from.innerWidth(), 
			height:	from.outerHeight()
		};
		var dummy = $('<div data-role="page"/>').insertBefore(from).css({
			width:	Math.max(parseInt(toDim.width, 10), parseInt(fromDim.width, 10)) + 'px', 
			height:	(Math.max(parseInt(toDim.height, 10), parseInt(fromDim.height, 10)) - 2) + 'px'
		});

		// 2. Position pages in transition absolutely
		from.css({
			position: 'absolute', 
			left: 0, 
			top: 0, 
			width: fromDim.iWidth + 'px'
		});

		to.css({
			position: 'absolute', 
			left: 0, 
			top: 0, 
			width: toDim.iWidth + 'px'
		});

		// 3. Give pages in transition appropriate classes
		var oldClasses		= to.attr('class');
		var wrapOldClasses	= wrap.attr('class');

		// Start
		wrap.addClass('sleek-mobile-transition-' + trans + '-wrapper');
		from.addClass('sleek-mobile-transition-' + trans + '-out-' + rev + 'start');
		to.addClass('sleek-mobile-transition-' + trans + '-in-' + rev + 'start');

		// End
		setTimeout(function () {
			from.addClass('sleek-mobile-transition sleek-mobile-transition-' + trans + ' sleek-mobile-transition-' + trans + '-out-' + rev + 'end');
			to.addClass('sleek-mobile-transition sleek-mobile-transition-' + trans + ' sleek-mobile-transition-' + trans + '-in-' + rev + 'end');
		}, 1);

		// 4. Once the .class-based transitions are finished...
		setTimeout(function () {
			SleekMobile.log('Transition complete');

			from.remove();
			dummy.remove();

			to.css({position: 'static', width: 'auto'}).attr('class', oldClasses || '');
			wrap.attr('class', wrapOldClasses || '');

			SleekMobile.runPageLoadCallbacks(to.attr('id'), to);
		}, SleekMobile.transitionDuration + 1);
	}
};
